<?php
/**
 * This file defines the static class '\BF\TypeTool'.
 *
 * @author     Kado <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @package    BF\Core
 * @since      2015-01-17 14:29
 * @subpackage Helpers
 * @version    0.1
 */

namespace BF
{

   /**
    * This is a static helper class, to better handle some PHP type juggling.
    *
    * @since  v0.1
    */
   class TypeTool
   {

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R I V A T E   S T A T I C   F I E L D S   - - - - - - - - - - - - - - -">

      /**
       * This is the regular expresion to check if a string can be used as integer value.
       *
       * @var string
       */
      private static $rxInt32 = '~^-?(0|[1-9]\d{0,11})$~';

      /**
       * This is the regular expresion to check if a string can be used as big integer or long value.
       *
       * @var string
       */
      private static $rxInt64 = '~^-?(0|[1-9]\d{0,19})$~';

      /**
       * This is the regular expresion to check if a string can be used as double precission value,
       * with a dot as decimal separator.
       *
       * @var string
       */
      private static $rxD1 = '~^-?((0|[1-9]\d{0,20})?\.\d{0,14}|\.\d{0,14})$~';

      /**
       * This is the regular expresion to check if a string can be used as decimal value,
       * with a dot or comma as decimal separator.
       *
       * @var string
       */
      private static $D    = '~^-?((0|[1-9]\d{0,20})?(\.|,)\d{0,14}|(\.|,)\d{1,14})$~';

      /**
       * This is the regular expresion to check if a string can be used a boolean TRUE value.
       *
       * @var string
       */
      private static $rxBoolTRUE = '~^(true|on|yes|enabled)$~i';

      /**
       * This is the regular expresion to check if a string can be used a boolean FALSE value.
       *
       * @var string
       */
      private static $rxBoolFALSE = '~^(false|off|no|disabled)$~i';

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - >   P R I V A T E   C O N S T R U C T O R   - - - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance.
       * @ignore
       */
      public function __construct() { }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   S T A T I C   M E T H O D S   - - - - - - - - - - - - - - -">

      /**
       * Returns if the defined value is usable as integer value.
       *
       * @param  mixed $value The value to check
       * @return boolean
       */
      public static function IsInteger( $value )
      {
         return (bool) \preg_match( self::$rxInt32, \strval( $value ) );
      }

      /**
       * Returns if the defined value is usable as a decimal value.
       *
       * @param  mixed   $value            The value to check.
       * @param  boolean $cultureInvariant If TRUE, also the comma can be used as decimal separator.
       * @return boolean
       */
      public static function IsDecimal( $value, $cultureInvariant = false )
      {
         if ( \preg_match( self::$rxInt64, \strval($value) ) )
         {
            return true;
         }
         if ( ! $cultureInvariant )
         {
            return (bool) \preg_match( self::$rxD1, \strval( $value ) );
         }
         return (bool) \preg_match( self::$D, \strval( $value ) );
      }

      /**
       * Returns if the defined value is usable as a boolean value. If so, $resultingBoolValue returns the resulting
       * boolean value.
       *
       * @param  mixed   $value              The value to check.
       * @param  boolean $resultingBoolValue Returns the resulting boolean value, if the method returns TRUE
       * @return boolean
       */
      public static function IsBoolConvertible( $value, &$resultingBoolValue )
      {
         if ( \is_null( $value ) )
         {
            $resultingBoolValue = false;
            return false;
         }
         if ( \is_bool( $value ) )
         {
            $resultingBoolValue = $value;
            return true;
         }
         if ( \is_resource( $value ) )
         {
            $resultingBoolValue = true;
            return true;
         }
         if ( \is_object( $value ) )
         {
            $resultingBoolValue = false;
            return false;
         }
         if ( \is_array( $value ) )
         {
            $resultingBoolValue = \count( $value ) > 0;
            return true;
         }
         if ( self::IsInteger( $value ) )
         {
            $resultingBoolValue = ( \intval( $value ) > 0 );
            return true;
         }
         if ( self::IsDecimal( $value ) )
         {
            $resultingBoolValue = ( \doubleval( $value ) > 0 );
            return true;
         }
         $strval = \strval( $value );
         if ( \preg_match( self::$rxBoolTRUE, $strval ) )
         {
            $resultingBoolValue = true;
            return true;
         }
         if ( \preg_match( self::$rxBoolFALSE, $strval ) )
         {
            $resultingBoolValue = false;
            return true;
         }
         if ( \preg_match( '~^b:[01];$~', $strval ) )
         {
            // A serialized boolean value
            $resultingBoolValue = \unserialize( $strval );
            return true;
         }
         if ( \strlen( $strval ) < 1 )
         {
            $resultingBoolValue = false;
            return true;
         }
         $resultingBoolValue = false;
         return false;
      }

      /**
       * Returns if the defined value is usable as a string value. If so, $resultingString returns the resulting
       * string value.
       *
       * @param  mixed   $value           The value to check.
       * @param  string  $resultingString Returns the resulting string value, if the method returns TRUE
       * @return boolean
       */
      public static function IsStringConvertible( $value, &$resultingString )
      {
         if ( \is_null( $value ) )
         {
            $resultingString = '';
            return true;
         }
         if ( \is_string( $value ) )
         {
            $resultingString = $value;
            return true;
         }
         if ( \is_bool( $value ) )
         {
            $resultingString = $value ? 'true' : 'false';
            return true;
         }
         if ( \is_resource( $value ) )
         {
            $resultingString = '';
            return false;
         }
         if ( \is_object( $value ) )
         {
            if ( \method_exists( $value, '__toString' ) )
            {
               $resultingString = (string) $value;
               return true;
            }
            if ( $value instanceof \DateTime )
            {
               $resultingString = $value->format( 'Y-m-d H:i:s' );
               return true;
            }
            $resultingString = '';
            return false;
         }
         if ( \is_array( $value ) )
         {
            $resultingString = \serialize( $value );
            return true;
         }
         if ( is_int( $value ) )
         {
            $resultingString = \strval( $value );
            return true;
         }
         if ( self::IsDecimal( $value ) )
         {
            $resultingString = \strval( $value );
            return true;
         }
         $resultingString = '';
         return false;
      }

      /**
       * Converts a string to defined native PHP type.
       *
       * @param  string $string   The string to convert
       * @param  string $typename The name of the required resulting PHP type.
       *         Allowed types are (bool|boolean|double|float|int|integer|string|array)
       * @return mixed
       */
      public static function StrToType( $string, $typename )
      {

         if ( null === $string )
         {
            return null;
         }

         $t = new \BF\Type( $string );
         if ( ! $t->hasAssociatedString() )
         {
            return null;
         }

         $string = $t->getStringValue();

         switch ( \strtolower( $typename ) )
         {
            case 'bool':
            case 'boolean':
               $res = false;
               self::IsBoolConvertible( $string, $res );
               return $res;
            case 'float':
               return \floatval( \str_replace( ',', '.', $string ) );
            case 'double':
               if ( ! self::IsDecimal( $string, true ) )
               {
                  return null;
               }
               $res = \str_replace( ',', '.', $string );
               $tmp = \explode( '.', $res );
               $ts  = \count( $tmp );
               if ( $ts > 2 )
               {
                  $dv = $tmp[ $ts - 1 ];
                  unset ( $tmp[ $ts - 1 ] );
                  $dv = \join( '', $tmp ) . '.' . $dv;
                  return \doubleval( $dv );
               }
               return \doubleval( $res );
            case 'int':
            case 'integer':
               if ( self::IsInteger( $string ) || self::IsDecimal( $string, true ) )
               {
                  return \intval( $string );
               }
               return null;
            case 'string':
               return $string;
            case 'array':
               if ( \strlen( $string ) < 1 )
               {
                  return array();
               }
               if ( \strlen( $string ) > 3 )
               {
                  if ( \substr( $string, 0, 2 ) == 'a:' )
                  {
                     try
                     {
                        $res = \unserialize( $string );
                        if ( \is_array( $res ) )
                        {
                           return $res;
                        }
                     }
                     catch ( \Exception $ex ) { }
                  }
                  if ( \BF\str_startswith( $string, '[' )
                    && \BF\str_endswith( $string, ']' ))
                  {
                     try { return (array) \json_decode( $string ); }
                     catch ( \Exception $ex ) { }
                  }
                  else if ( \BF\str_startswith( $string, '{' )
                         && \BF\str_endswith( $string, '}' ))
                  {
                     try { return (array) \json_decode( $string ); }
                     catch ( \Exception $ex ) { }
                  }
               }
               return array( $string );
            default:
               if ( \strlen( $string ) < 1 )
               {
                  return null;
               }
               if ( \strlen( $string ) > 3 )
               {
                  if ( \substr( $string, 0, 2 ) == 'O:' &&
                       \preg_match( '~^O:[^"]+"' . $typename . '":~', $string ) )
                  {
                     try
                     {
                        $res = \unserialize( $string );
                        if ( ! \is_object( $res ) )
                        {
                           return null;
                        }
                        if ( \get_class( $res ) == $typename )
                        {
                           return $res;
                        }
                     }
                     catch ( \Exception $ex ) { }
                  }
               }
               return null;
         }
      }

      /**
       * Extracts typed data from defined XML element.
       *
       * For it, the XML element must define the data of a single value.
       *
       * The type name can be defined by 'type' attribute or by the
       * &lt;Type&gt;Typename&lt;/Type&gt; element.
       *
       * The type value can be defined as string by 'value' attribute or by the
       * &lt;Value&gt;A value&lt;/Value&gt; element, or by the string value defined
       * inside the XML element it self. (&lt;XmlElement type="..."&gt;A Value&lt;/XmlElement&gt;)
       *
       * @param  \SimpleXMLElement $xmlelement The XML element defining the typed value.
       * @return mixed The typed value, or NULL if no usable data are defined
       */
      public static function XmlToType( \SimpleXMLElement $xmlelement )
      {
         $type = null;
         $value = null;
         if ( isset( $xmlelement['type'] ) )
         {
            $type = (string) $xmlelement['type'];
         }
         elseif ( isset( $xmlelement[ '@attributes' ][ 'type' ] ) )
         {
            $type = (string) $xmlelement[ '@attributes' ][ 'type' ];
         }
         elseif ( isset( $xmlelement[ 'attributes' ][ 'type' ] ) )
         {
            $type = (string) $xmlelement[ 'attributes' ][ 'type' ];
         }
         elseif ( isset( $xmlelement->{'@attributes'}[ 'type' ] ) )
         {
            $type = (string) $xmlelement->{'@attributes'}[ 'type' ];
         }
         elseif ( isset( $xmlelement->type ) )
         {
            $type = (string)$xmlelement->type;
         }
         elseif ( isset( $xmlelement->Type ) )
         {
            $type = (string) $xmlelement->Type;
         }
         else
         {
            return $value;
         }
         if ( isset( $xmlelement[ 'value' ] ) )
         {
            $value = (string) $xmlelement[ 'value' ];
         }
         elseif ( isset( $xmlelement[ '@attributes' ][ 'value' ] ) )
         {
            $value = (string) $xmlelement[ '@attributes' ][ 'value' ];
         }
         elseif ( isset( $xmlelement[ 'attributes' ][ 'value' ] ) )
         {
            $value = (string) $xmlelement[ 'attributes' ][ 'value' ];
         }
         elseif ( isset( $xmlelement->{'@attributes'}[ 'value' ] ) )
         {
            $value = (string) $xmlelement->{'@attributes'}[ 'value' ];
         }
         elseif ( isset( $xmlelement->value ) )
         {
            $value = (string) $xmlelement->value;
         }
         elseif ( isset( $xmlelement->Value ) )
         {
            $value = (string) $xmlelement->Value;
         }
         else
         {
            $value = (string) $xmlelement;
         }
         return self::StrToType( $value, $type );
      }

      /**
       * Writes all data of the defined Value to the XmlWriter.
       *
       * You can write it in 3 diffent ways:
       *
       * - &lt;$name type="..." value="..." /&gt;
       *   Is created if $short is boolean TRUE.
       *
       * If $short is FALSE you can write in the following 2 ways:
       *
       * - &lt;$name type="..."&gt;$value&lt;/$name&gt;
       *   Is created if $separateElements is boolean FALSE.
       * - &lt;$name&gt;&lt;Type&gt;...&lt;/Type&gt;&lt;Value&gt;$value&lt;/Value&gt;&lt;/$name&gt;
       *   Is created if $separateElements is boolean TRUE.
       *
       * @param \XMLWriter $w                The XmlWriter to use.
       * @param mixed      $value            The value to write.
       * @param string     $name             The name of the element to write
       * @param boolean    $short            Use the short notation? (type and value as attributes)
       * @param boolean    $separateElements Write type and value in separate elements, if $short is FALSE
       */
      public static function WriteTypedXmlValue( \XMLWriter $w, $value, $name, $short = true, $separateElements = false)
      {
         if ( ! ( $value instanceof \BF\Type ) )
         {
            $value = new \BF\Type( $value );
         }
         $v = null;
         $t = null;
         switch ( $value->getType() )
         {
            case \BF\Type::PHP_ARRAY:
               $v = \serialize( $value->getValue() );
               $t = \BF\Type::PHP_ARRAY;
               break;
            case \BF\Type::PHP_BOOLEAN:
               $v = $value->getValue() ? 'true' : 'false';
               $t = \BF\Type::PHP_BOOLEAN;
               break;
            case \BF\Type::PHP_DOUBLE:
            case \BF\Type::PHP_FLOAT:
            case \BF\Type::PHP_INTEGER:
               $v = $value->getValue();
               $t = $value->getType();
               break;
            case \BF\Type::PHP_NULL:
               $v = '';
               $t = \BF\Type::PHP_NULL;
               break;
            case \BF\Type::PHP_RESOURCE:
                # Ignore some resources
               break;
            case \BF\Type::PHP_STRING:
               $v = $value->getValue();
               $t = \BF\Type::PHP_STRING;
               break;
            case \BF\Type::PHP_UNKNOWN:
               $v = $value->getStringValue();
               $t = \BF\Type::PHP_STRING;
               break;
            default:
               $v = \serialize( $value->getValue() );
               $t = $value->getType();
               break;
         }
         if ( ! \is_null( $t ) && ! \is_null( $v ) )
         {
            $w->startElement( $name );
            if ( $short )
            {
               $w->writeAttribute( 'type', $t );
               $w->writeAttribute( 'value', $v );
            }
            else
            {
               if ( $separateElements )
               {
                  $w->writeElement( 'type',  $t );
                  $w->writeElement( 'value', $v );
               }
               else
               {
                  $w->writeAttribute( 'type', $t );
                  $w->text( $v );
               }
            }
            $w->endElement();
         }
      }

      /**
       * Returns if the type of defined value is a nativ PHP type.
       *
       * Native types are: boolean, integer, double, float, string, array
       *
       * @param  mixed $value THe value to check.
       * @return boolean
       */
      public static function IsNativeType( $value )
      {
         return (
               \is_bool(   $value )
            || \is_int(    $value )
            || \is_string( $value )
            || \is_double( $value )
            || \is_float(  $value )
            || \is_array(  $value )
         );
      }

      /**
       * Converts a value of type null, int, float, double, bool, \BF\DateTime, array or object
       * to a XML-Definition.
       *
       * The 'name' attribute of the created XML element is defined by the $element parameter.
       *
       * For example, the resulting XML locks like this:
       *
       * <code>&lt;element name="age" type="int"&gt;30&lt;/element&gt;</code>
       *
       * if TypeToXml(30, 'age') is called.
       *
       * If the 3rd parameter $forceShortXml is boolean TRUE, for types NULL, integer, double, float, boolean
       * and \BF\DateTime a XML-Element with the following format is created:
       *
       * <code>&lt;element name="age" type="int" value="30"/&gt;</code>
       *
       * @param  mixed   $value         The value to save as XML element.
       * @param  string  $element       The 'name' attribute of the resulting XML element.
       * @param  boolean $forceShortXml For types NULL, integer, double, float, boolean and \BF\DateTime
       *                                short XML syntax is forced?
       * @return string XML string or boolean FALSE if the value type is 'resource'.
       */
      public static function TypeToXml2( $value, $element, $forceShortXml = false )
      {
         if ( \is_resource( $value ) )
         {
            return false;
         }
         if ( \is_null( $value ) )
         {
            return \sprintf( '<element name="%s" type="NULL" />', $element );
         }
         if ( \is_int( $value ) || \is_double( $value ) || \is_float( $value ) )
         {
            return ( $forceShortXml
               ? \sprintf(
                  '<element name="%s" type="%s" value="%s"/>',
                  $element,
                  \gettype( $value ),
                  \strval( $value )
               )
               : \sprintf(
                  '<element name="%s" type="%s">%s</element>',
                  $element,
                  \gettype( $value ),
                  \BF\mask_xml( \strval( $value ) )
               )
            );
         }
         if ( \is_bool( $value ) )
         {
            return ( $forceShortXml
               ? \sprintf(
                  '<element name="%s" type="bool" value="%s"/>',
                  $element,
                  ( $value ? '1' : '0' )
               )
               : \sprintf(
                  '<element name="%s" type="bool">%s</element>',
                  $element,
                  ( $value ? '1' : '0' )
               )
            );
         }
         if ( $value instanceof \BF\DateTime )
         {
            return ( $forceShortXml
               ? \sprintf(
                  '<element name="%s" type="\\BF\\DateTime" value="%s"/>',
                  $element,
                  $value->stamp
               )
               : \sprintf(
                  '<element name="%s" type="\\BF\\DateTime">%s</element>',
                  $element,
                  $value->stamp
               )
            );
         }
         if ( \is_array( $value ) || \is_object( $value ) )
         {
            $t = \is_array( $value ) ? 'array' : 'object';
            return \sprintf(
               '<element name="%s" type="%s"><![CDATA[%s]]></element>',
               $element,
               $t,
               \serialize( $value )
            );
         }
         try
         {
            $strval = \strval( $value );
            return \sprintf(
               '<element name="%s" type="string"><![CDATA[%s]]></element>',
               $element,
               $strval
            );
         }
         catch ( \Exception $ex ) { $ex = null; return ""; }
      }

      /**
       * Converts a XML element that defines a typed value into the associated value.
       *
       * Requires a XML with the following format:
       *
       * <code>&lt;element name="age" type="int" value="30"/&gt;</code>
       *
       * or:
       *
       * <code>&lt;element name="age" type="int"&gt;30&lt;/element&gt;</code>
       *
       * @param  \SimpleXMLElement $xmlelement The XmlElement.
       * @param  array             $resultSet  The array where the resulting value should be stored.
       * @throws \BF\ArgumentFormatException If the attributes 'name' or 'type' are undefined.
       */
      public static function XmlToType2( \SimpleXMLElement $xmlelement, array &$resultSet )
      {
         if ( ! isset( $xmlelement[ 'name' ] ) || ! isset( $xmlelement[ 'type' ] ) )
         {
            throw new \BF\ArgumentFormatException(
                'xmlelement', $xmlelement,
                'Not enougth xml element attributes! Converting a SimpleXMLElement into a typed value fails.'
            );
         }
         if ( isset( $xmlelement[ 'value' ] ) )
         {
            $resultSet[ (string) $xmlelement[ 'name' ] ] = self::StrToType(
                (string) $xmlelement[ 'value' ],
                (string) $xmlelement[ 'type' ]
            );
            return;
         }
         $resultSet[ (string) $xmlelement[ 'name' ] ] = self::StrToType(
            (string) $xmlelement,
            (string) $xmlelement[ 'type' ]
         );
      }

      /**
       * Returns the native type name of the defined value.
       *
       * @param  mixed $value The value.
       * @return string Returns the name of the type (see \BF\Type::PHP_* constants) or boolean FALSE if the value has not native type
       */
      public static function GetNativeType( $value )
      {
         if ( \is_string( $value ) )
         {
            return \BF\Type::PHP_STRING;
         }
         if ( \is_int( $value ) )
         {
            return \BF\Type::PHP_INTEGER;
         }
         if ( \is_bool( $value ) )
         {
            return \BF\Type::PHP_BOOLEAN;
         }
         if ( \is_double( $value ) )
         {
            return \BF\Type::PHP_DOUBLE;
         }
         if ( \is_float( $value ) )
         {
            return \BF\Type::PHP_FLOAT;
         }
         return false;
      }

      /**
       * Returns the type name of the defined value.
       *
       * @param  mixed $value The value.
       * @return string
       */
      public static function GetTypeName( $value )
      {
         if ( \is_null( $value ) )
         {
            return \BF\Type::PHP_NULL;
         }
         if ( \is_object( $value ) )
         {
            return \get_class( $value );
         }
         if ( \is_string( $value ) )
         {
            return \BF\Type::PHP_STRING;
         }
         if ( \is_int( $value ) )
         {
            return \BF\Type::PHP_INTEGER;
         }
         if ( \is_bool( $value ) )
         {
            return \BF\Type::PHP_BOOLEAN;
         }
         if ( \is_double( $value ) )
         {
            return \BF\Type::PHP_DOUBLE;
         }
         if ( \is_float( $value ) )
         {
            return \BF\Type::PHP_FLOAT;
         }
         if ( \is_resource( $value ) )
         {
            return \BF\Type::PHP_RESOURCE;
         }
         if ( \is_array( $value ) )
         {
            return \BF\Type::PHP_ARRAY;
         }
         return \BF\Type::PHP_UNKNOWN;
      }

      /**
       * Converts the value! It must be a native PHP type (bool, int, float, double, string) to a other native PHP type.
       *
       * @param  mixed  $sourceValue The value to convert
       * @param  string $newType Native PHP type as target type. (See \BF\Type::PHP_* constants)
       * @return mixed
       * @throws \BF\ArgumentOutOfRangeException
       */
      public static function ConvertNative( $sourceValue, $newType )
      {
         if ( \is_null( $sourceValue ) )
         {
            return $sourceValue;
         }
         if ( false === ( $sourceType = self::GetNativeType( $sourceValue ) ) )
         {
            throw new \BF\ArgumentOutOfRangeException(
               'sourceValue',
               $sourceValue,
               'Can not convert a value of a type that isnt a native PHP type! (bool, int, double, float, string)'
            );
         }
         if ( $sourceType == $newType )
         {
            return $sourceValue;
         }
         switch ( $sourceType )
         {
            case \BF\Type::PHP_BOOLEAN:
               switch ( $newType )
               {
                  case \BF\Type::PHP_DOUBLE:
                     return (double) ( $sourceValue ? 1 : 0 );
                  case \BF\Type::PHP_FLOAT:
                     return (float) ( $sourceValue ? 1 : 0 );
                  case \BF\Type::PHP_INTEGER:
                     return ( $sourceValue ? 1 : 0 );
                  case \BF\Type::PHP_STRING:
                     return ( $sourceValue ? '1' : '0' );
               }
               break;
            case \BF\Type::PHP_DOUBLE:
               switch ( $newType )
               {
                  case \BF\Type::PHP_FLOAT:
                     return \doubleval( $sourceValue );
                  case \BF\Type::PHP_INTEGER:
                     return \intval( $sourceValue );
                  case \BF\Type::PHP_STRING:
                     return '' . $sourceValue;
                  case \BF\Type::PHP_BOOLEAN:
                     return $sourceValue > 0;
               }
               break;
            case \BF\Type::PHP_FLOAT:
               switch ( $newType )
               {
                  case \BF\Type::PHP_DOUBLE:
                     return \floatval( $sourceValue );
                  case \BF\Type::PHP_INTEGER:
                     return \intval( $sourceValue );
                  case \BF\Type::PHP_STRING:
                     return '' . $sourceValue;
                  case \BF\Type::PHP_BOOLEAN:
                     return $sourceValue > 0;
               }
               break;
            case \BF\Type::PHP_INTEGER:
               switch ( $newType )
               {
                  case \BF\Type::PHP_DOUBLE:
                     return \intval( $sourceValue );
                  case \BF\Type::PHP_FLOAT:
                     return \intval( $sourceValue );
                  case \BF\Type::PHP_STRING:
                     return '' . $sourceValue;
                  case \BF\Type::PHP_BOOLEAN:
                     return $sourceValue > 0;
               }
               break;
            case \BF\Type::PHP_STRING:
               switch ( $newType )
               {
                  case \BF\Type::PHP_INTEGER:
                  case \BF\Type::PHP_BOOLEAN:
                  case \BF\Type::PHP_FLOAT:
                  case \BF\Type::PHP_DOUBLE:
                     return \BF\TypeTool::StrToType($sourceValue, $newType);
               }
               break;
         }
         throw new \BF\ArgumentOutOfRangeException(
            'newType',
            $newType,
            'Can not convert a value of a type that isnt a native PHP type! (bool, int, double, float, string)'
         );
      }

      # </editor-fold>

   }

}

